﻿// import js from '@eslint/js'
import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginPrettier from 'eslint-plugin-prettier/recommended'
import stylisticJs from '@stylistic/eslint-plugin-js'
import eslintPluginVue from 'eslint-plugin-vue'

export default [
  {
    ignores: ['node_modules/', 'dist/', 'public/', 'src/assets/', 'tests/'],
  },
  {
    ...eslintPluginPrettier,
    rules: {
      ...eslintPluginPrettier.rules,
      ...eslintConfigPrettier.rules,

      'prettier/prettier': [
        'error',
        {
          semi: false,
          trailingComma: 'all',
          singleQuote: true,
          printWidth: 80,
          bracketSpacing: true,

          endOfLine: 'auto',
          useTabs: false,
          quoteProps: 'as-needed',
          jsxSingleQuote: false,
          jsxBracketSameLine: false,
          rangeStart: 0,
          requirePragma: false,
          insertPragma: false,
          proseWrap: 'preserve',
          htmlWhitespaceSensitivity: 'css',
          arrowParens: 'always',
          bracketSameLine: false,
          vueIndentScriptAndStyle: true,
        },
      ],
    },
  },

  // off:0 关闭规则,warn:1 警告规则,error:2 错误规则
  {
    files: ['src/**/*.{js,ts,jsx,tsx,vue}'],
    rules: {
      // 禁用 if、for、while 和 do...while 测试条件中的模糊赋值运算符。
      'no-cond-assign': ['error', 'always'],

      // 要求尽可能使用单引号
      quotes: ['error', 'single'],

      // 文件不得以 Unicode BOM 开头
      'unicode-bom': ['error', 'never'],

      // 骆驼大写风格
      camelcase: 'error',

      // this的别名只能是self
      'consistent-this': ['error', 'self'],

      // 禁止使用 eval()
      'no-eval': 'error',

      // 禁止将变量初始化为undefined
      'no-undef-init': 'error',

      'no-with': 'error',

      'prefer-template': 'error',
    },
  },

  // ESlint 风格
  {
    plugins: {
      '@stylistic/js': stylisticJs,
    },
    rules: {
      'spaced-comment': ['error', 'always'],

      'lines-between-class-members': ['error', 'always'],

      // 注释
      // 行注释的位置 只在代码上方
      'line-comment-position': ['error', { position: 'above' }],

      'lines-around-comment': [
        'error',
        {
          // 块状注释之前有一个空行
          beforeBlockComment: true,

          // 要求在行注释之前有一个空行
          beforeLineComment: true,

          // 允许注释出现在块语句、函数体、类、开关语句和类静态块的开头
          allowBlockStart: true,

          // 允许注释出现在对象字面的开头
          allowObjectStart: true,

          // 允许注释出现在数组字词的开始处
          allowArrayStart: true,

          // 允许注释出现在类的开始部分
          allowClassStart: true,
        },
      ],

      // // 或 /* 后面有空格
      // 'spaced-comment': ['error', 'always'],

      // 类成员之间强制空行，来提高可读性
      'lines-between-class-members': ['error', 'always'],

      // 添加或修改以下规则
      'padding-line-between-statements': [
        'error',

        // 在函数之前插入空白行
        { blankLine: 'always', prev: '*', next: 'function' },

        // 在函数之后插入空白行
        { blankLine: 'always', prev: 'function', next: '*' },
      ],
    },
  },

  // PluginVue
  ...eslintPluginVue.configs['flat/recommended'],
  {
    rules: {
      // 要求组件名称始终为多词
      // 注意:文件名也需要为多词
      'vue/multi-word-component-names': [
        2,
        {
          ignores: ['base', 'body', 'login', 'index', 'filter', 'edit', 'tree'],
        },
      ],

      // prettier 会根据是否有80字符格式化,不需要PluginVue处理
      'vue/max-attributes-per-line': [
        0,
        {
          singleline: {
            max: 1,
          },
          multiline: {
            max: 1,
          },
        },
      ],

      // 不允许在watch中使用箭头函数,Arrow 函数绑定到它们的父上下文，这意味着它们将无法通过 this访问 Vue 组件实例。
      'vue/no-arrow-functions-in-watch': [2],

      // 防止在计算属性和函数中调用异步方法
      // 调用是没有问题的,问题是不能返回一个promise.
      'vue/no-async-in-computed-properties': [0],

      // 重复的属性名称
      'vue/no-dupe-keys': [0],

      // 自定义组件上强制执行属性命名样式 my-prop="prop"
      /*
      <template>
          <!-- ✓ GOOD -->
          <MyComponent my-prop="prop" />

          <!-- ✗ BAD -->
          <MyComponent myProp="prop" />
        </template>
       */
      // 'vue/attribute-hyphenation': [0],

      // 组件名称  PascalCase |  kebab-case
      'vue/component-definition-name-casing': [2, 'kebab-case'],

      // 关闭标记括号之前强制执行一致的间距样式。
      'vue/html-closing-bracket-newline': [
        2,
        {
          singleline: 'never',
          multiline: 'always',
          selfClosingTag: {
            singleline: 'never',
            multiline: 'always',
          },
        },
      ],

      'vue/html-end-tags': [1],

      // 使用自闭合标签
      'vue/html-self-closing': [
        2,
        {
          html: {
            void: 'any',
            normal: 'always',
            component: 'always',
          },
          svg: 'always',
          math: 'always',
        },
      ],

      // 这条规则要求在多行元素的内容前后强制执行换行。这意味着如果有一个元素的内容跨越多行，那么在内容的每一行之前和之后都应该有换行符，以保持代码的整洁和易读性。这通常应用于编程语言中的多行字符串或者多行元素定义中。在 Vue 和 JavaScript 代码中，这样的规则有助于提高代码的可维护性和可读性。
      /*
        <!-- ✗ BAD -->
        <div>multiline
          content</div>
       */
      'vue/multiline-html-element-content-newline': [
        1,
        {
          ignoreWhenEmpty: true,
          ignores: ['pre', 'textarea'],
          allowEmptyLines: false,
        },
      ],

      'vue/singleline-html-element-content-newline': [
        'off',
        {
          ignoreWhenNoAttributes: true,
          ignoreWhenEmpty: true,
          ignores: ['pre'],
          externalIgnores: [],
        },
      ],

      // prop 强制默认值
      'vue/require-default-prop': 0,

      // 属性顺序
      'vue/attributes-order': [
        'error',
        {
          order: [
            'DEFINITION',
            'LIST_RENDERING',
            'CONDITIONALS',
            'RENDER_MODIFIERS',
            'GLOBAL',
            ['UNIQUE', 'SLOT'],
            'TWO_WAY_BINDING',
            'OTHER_DIRECTIVES',
            'OTHER_ATTR',
            'EVENTS',
            'CONTENT',
          ],
          alphabetical: true,
        },
      ],

      // 组件属性顺序
      'vue/order-in-components': [
        'error',
        {
          order: [
            'el',
            'name',
            'key',
            'parent',
            'functional',
            ['delimiters', 'comments'],
            ['components', 'directives', 'filters'],
            'extends',
            'mixins',
            ['provide', 'inject'],
            'ROUTER_GUARDS',
            'layout',
            'middleware',
            'validate',
            'scrollToTop',
            'transition',
            'loading',
            'inheritAttrs',
            'model',
            ['props', 'propsData'],
            'emits',
            'setup',
            'asyncData',
            'data',
            'fetch',
            'head',
            'computed',
            'watch',
            'watchQuery',
            'LIFECYCLE_HOOKS',
            'methods',
            ['template', 'render'],
            'renderError',
          ],
        },
      ],

      // 'template', 'script', 'style' 顺序
      'vue/block-order': [
        'error',
        {
          order: ['template', 'script', 'style'],
        },
      ],

      'vue/define-macros-order': [
        'error',
        {
          order: ['defineEmits', 'defineProps'],
          defineExposeLast: false,
        },
      ],

      // 这条规则旨在确保 Vue 组件中的多行属性之间有换行，
      'vue/new-line-between-multi-line-property': [
        'error',
        {
          minLineOfMultilineProperty: 2,
        },
      ],

      // 在块之间填充行
      'vue/padding-line-between-blocks': ['error', 'always'],

      // 在同级标记之间使用换行符
      'vue/padding-line-between-tags': [
        'error',
        [{ blankLine: 'always', prev: '*', next: '*' }],
      ],

      'vue/no-template-shadow': [0],
    },
  },
]
